HOME/Articles/

2017-7-31 python 生成器(Generators)

Article Outline

可迭代对象(iterable):

能提供迭代器的任意对象;只要定义了一个迭代器的iter方法或定义了支持下标索引的getitem方法,那就是一个可迭代对象。

迭代器(iterators):

任意对象,只要定义了next或者next方法,那就是一个迭代器

迭代(iteration):

从某个地方(如列表)取出一个元素的过程;使用一个循环来遍历某个东西(如列表),这个过程就是迭代;

<!--more-->

生成器(Generators):

也是一种迭代器,但只能对其迭代一次

  • 因为它们并没有把所有值存在内存中,而是运行时生成值;
  • 可通过遍历使用它们,要么使用“for”循环,要么传递给任意可以进行迭代的函数和结构;
  • 大多时候生成器是以函数实现的,但它们并不返回一个值,而是yield(生出)一个值。
    def generator_function():
     for i in range(10):
         yield i

for item in generator_function(): print(item)

Output: 0

1

2

3

4

5

6

7

8

9

#### 适用场景:
> 不想同一时间将所有计算出来的大量结果集分配到内存当中,特别是结果集里还包含循环;因为这样做会消耗大量资源 
> 许多Python 2里的标准库函数都会返回列表,而Python 3都修改成了返回生成器,因为生成器占用更少的资源。

**斐波那契数列的生成器:

```python
# 传统模式
def fibon(n):
    a = b = 1
    result = []
    for i in range(n):
        result.append(a)
        a, b = b, a + b
    return result

# 生成器模式
def fibon(n):
    a = b = 1
    for i in range(n):
        yield a
        a, b = b, a + b

# Now we can use it like this:
for x in fibon(1000000):
    print(x)

Python内置函数:next()

它允许我们获取一个序列的下一个元素 特点:

  • yield掉所有的值后,next()会触发一个StopIteration的异常。提示我们所有的值都已经被yield完了;
  • 在使用for循环时没有这个异常,因为for循环会自动捕捉到这个异常并停止调用next()
    def generator_function():
      for i in range(3):
          yield i

gen = generator_function() print(next(gen))

Output: 0

print(next(gen))

Output: 1

print(next(gen))

Output: 2

print(next(gen))

Output: Traceback (most recent call last):

File "<stdin>", line 1, in <module>

StopIteration



### Python内置函数:`iter()`
> 将一个可迭代对象返回一个迭代器对象
```python
my_string = "Bingo"
next(my_string)
# Output: Traceback (most recent call last):
#      File "<stdin>", line 1, in <module>
#    TypeError: str object is not an iterator

这个异常说str对象是一个可迭代对象,而不是一个迭代器;不能直接对其进行迭代操作,所以,使用iter

my_string = "Bingo"
my_iter = iter(my_string)
next(my_iter)
# Output: 'B'
next(my_iter)
# Output: 'i'
next(my_iter)
# Output: 'n'
next(my_iter)
# Output: 'g'
next(my_iter)
# Output: 'o'
next(my_iter)
# Output: Traceback (most recent call last):
#         File "<stdin>", line 12, in <module>
#         StopIteration